/*
 *  Copyright 2010 Mahbub Mozadded Sowrov.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
/*
 * ParseSubmitPage.java
 * Date: Nov 24, 2010
 * Version: 1.0
 */


package com.sowrov.afrigis.tools.timesheet.parse.html;

import com.sowrov.afrigis.tools.timesheet.Activity;
import com.sowrov.afrigis.tools.timesheet.PostData;
import com.sowrov.afrigis.tools.timesheet.PostDataList;
import com.sowrov.afrigis.tools.timesheet.Project;
import com.sowrov.afrigis.tools.timesheet.User;
import com.sowrov.afrigis.tools.timesheet.parse.javascript.JavascriptParser;
import com.sowrov.util.logsystem.ChronicleLogger;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.lobobrowser.html.parser.DocumentBuilderImpl;
import org.lobobrowser.html.test.SimpleUserAgentContext;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.html2.HTMLDocument;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;


/**
 * <p>Instance of <code>ParseSubmitPage</code> is thread safe.</p>
 *
 * @author sowrov
 */
public class ParseSubmitPage {
    private static ParseSubmitPage instance = null;
    private SimpleUserAgentContext context = null;
    private DocumentBuilderImpl docBuilder = null;
    private ArrayList<Project> projects = null;

    private JavascriptParser jsParser = null;
    private String htmlCode = "";
    private String dateString = "01/01/1900";//day/month/year
    private PostDataList pdataList;

    private ParseSubmitPage() {
        this.context = new SimpleUserAgentContext();
        this.context.setAppName("Mozilla Firefox");
        this.context.setAppCodeName("Mozilla");
        this.context.setScriptingEnabled(false);
        this.context.setExternalCSSEnabled(false);
        this.pdataList = null;
        this.docBuilder = new DocumentBuilderImpl(this.context);
    }

    public static ParseSubmitPage getInstance() {
        if (ParseSubmitPage.instance == null) {
            ParseSubmitPage.instance = new ParseSubmitPage();
        }
        return ParseSubmitPage.instance;
    }

    public void setHtmlCode(String str, String dateString) {
        this.htmlCode = str;
        this.dateString = dateString;
    }

    public void setHtmlCode(String str) {
        this.htmlCode = str;
    }

    public void setStringDate(String dateString){
        this.dateString = dateString;
    }

    public ArrayList<Project> getProjects() {
        return projects;
    }

    public PostDataList getPostdataList() {
        return pdataList;
    }
    

    public void parse(boolean parsePosts, boolean parseProjectList) throws IOException, SAXException {
        if (this.htmlCode.equals("")) {
            throw new IOException("No Html code found");
        }
        if (!parsePosts && !parseProjectList) {
            return;
        }
        InputStream is = new ByteArrayInputStream(htmlCode.getBytes());
        HTMLDocument document = (HTMLDocument) this.docBuilder.parse(is);
        NodeList nlist = null;
        ArrayList<Node> tableRows = new ArrayList<Node>();
        nlist = document.getElementsByTagName("table");
        Node dataTable = nlist.item(1);
        NodeList dataTableChild = dataTable.getChildNodes();
        //collect all table tr fields
        for (int i = 0; i < dataTableChild.getLength(); i++) {
            if (dataTableChild.item(i).getNodeType() == 1) {
                tableRows.add(dataTableChild.item(i));
            }
        }

        if (tableRows.size()<5) {
            throw new IOException("Insufficient number of rows");
        }

        if (parsePosts) {
            ArrayList<Node> postRow = new ArrayList<Node>();
            for (int i = 2; i < tableRows.size() - 3; i++) {
                postRow.add(tableRows.get(i));
//                NodeList rowChild = tableRows.get(i).getChildNodes();
//                System.out.println(rowChild.getLength());
            }
            this.parserPostData(postRow);
            
        }
        if (parseProjectList) {
            Node fieldRow = tableRows.get(tableRows.size() - 2);

            nlist = document.getElementsByTagName("script");
            Node node = nlist.item(0);
            this.jsParser = new JavascriptParser(node.getTextContent());
            this.projects = this.jsParser.getProjects();
            this.parserProjectList(fieldRow);
        }
    }

    private void parserProjectList(Node fieldRow) {
                            //text -> td -> text -> td
        Node projectTd = fieldRow.getFirstChild().getNextSibling().getNextSibling().getNextSibling();
        Node selectList = projectTd.getFirstChild();
//        System.out.println(selectList.getNodeName()+" "+selectList.getTextContent());
        NodeList optionNodes = selectList.getChildNodes();
        ChronicleLogger.getInstance().logDebug("Found total projects: "+optionNodes.getLength());
        for (int i=0; i<optionNodes.getLength(); i++) {
            //System.out.println(optionNodes.item(i).getNodeName()+" "+optionNodes.item(i).getNodeType());
            if (optionNodes.item(i).getNodeType() == 1) {
                Node option = optionNodes.item(i);
                NamedNodeMap attributes = option.getAttributes();
                if (attributes != null && attributes.getNamedItem("title")!=null) {
                    String projectName = attributes.getNamedItem("title").getNodeValue();
                    String idRate = attributes.getNamedItem("value").getNodeValue();
                    StringTokenizer strTok = new StringTokenizer(idRate, "/");
                    String id = strTok.nextToken();
                    String rate = strTok.nextToken();
                    int j = 0;
                    for (j=0; j<this.projects.size(); j++) {
                        if(this.projects.get(j).getId().equals(id)) {
                            this.projects.get(j).setName(projectName);
                            this.projects.get(j).setRate(rate);
                            break;
                        }
                    }
                    if (j==this.projects.size()) {
                        System.out.println("Could not find project"+id);
                    }
                }
            }
        }
    }

    private void parserPostData(ArrayList<Node>postRow) {
        pdataList = new PostDataList();
        for (int i=0; i<postRow.size(); i++) {
            PostData pdata = new PostData();
            pdata.setLocalId(-1); //unknown;
            //get post id
            Node curTd = postRow.get(i).getFirstChild().getNextSibling();
            Node firstA = curTd.getFirstChild().getFirstChild().getNextSibling();
            StringTokenizer strtok = new StringTokenizer(firstA.getAttributes().item(0).getNodeValue(), "Default.asp?Record=&EDate/");
            pdata.setServerId(strtok.nextToken());
            
            //get project Id
            curTd = curTd.getNextSibling().getNextSibling();
            strtok = new StringTokenizer(curTd.getFirstChild().getTextContent(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
            pdata.setProjectId(strtok.nextToken());

            //get activity name
            curTd = curTd.getNextSibling().getNextSibling();
            Project project = User.getInstance().getProjectById(pdata.getProjectId());
            if (project != null) {
                String activityName = curTd.getFirstChild().getTextContent();
                Activity activity = project.getActivityByName(activityName);
                if (activity != null) {
                    pdata.setActivityId(activity.getId());
                } else {
                    ChronicleLogger.getInstance().logDebug("Activity Not found: '"+
                            activityName+"' for project: "+project.getName());
                }
            } else {
                ChronicleLogger.getInstance().logDebug("Project with project id "+pdata.getProjectId()+" not found");
            }

            //get type, Not Needed
            curTd = curTd.getNextSibling().getNextSibling();
//            System.out.println(curTd.getFirstChild().getTextContent());

            //get billable
            curTd = curTd.getNextSibling().getNextSibling();
            pdata.setBillable(curTd.getFirstChild().getTextContent().equalsIgnoreCase("Y")?true:false);

            //get Description
            curTd = curTd.getNextSibling().getNextSibling();
            pdata.setDescription(curTd.getFirstChild().getTextContent());

            //get hour
            curTd = curTd.getNextSibling().getNextSibling();
            pdata.setDecimalTime(curTd.getFirstChild().getTextContent());
            pdata.setStatus(2);
            pdata.setStrDate(this.dateString);
            pdataList.addPostData(pdata);
        }
    }

    public static void main(String args[]) throws FileNotFoundException, IOException, Exception {
        ParseSubmitPage parser = ParseSubmitPage.getInstance();
        FileReader fr = new FileReader("f:/dev/java/TimeSheetManager/test_input/ActivitySubmitPage3.htm");
        char[] cbuf = new char[1000];
        StringBuilder stringBuilder = new StringBuilder();
        while(fr.read(cbuf)!=-1) {
            stringBuilder.append(cbuf);
        }
        parser.setHtmlCode(stringBuilder.toString());
        parser.parse(true, false);
        System.out.println(parser.getPostdataList().getSize());
    }
}
